"""IPAM管理器."""

import ipaddress
from typing import List, Optional, Tuple

from sqlalchemy import select, func
from sqlalchemy.ext.asyncio import AsyncSession

from netsphere.models.ipam import IPAddress, IPNetwork, VLAN, VRF


class IPAMManager:
    """IPAM管理器，提供IP地址和网络的管理功能."""
    
    def __init__(self, session: AsyncSession):
        """初始化IPAM管理器.
        
        Args:
            session: 数据库会话
        """
        self.session = session
    
    async def create_vrf(self, name: str, rd: str, description: str = None) -> VRF:
        """创建VRF.
        
        Args:
            name: VRF名称
            rd: Route Distinguisher
            description: 描述信息
            
        Returns:
            VRF实例
        """
        vrf = VRF(name=name, rd=rd, description=description)
        self.session.add(vrf)
        await self.session.commit()
        return vrf
    
    async def create_vlan(self, vid: int, name: str, description: str = None) -> VLAN:
        """创建VLAN.
        
        Args:
            vid: VLAN ID
            name: VLAN名称
            description: 描述信息
            
        Returns:
            VLAN实例
        """
        vlan = VLAN(vid=vid, name=name, description=description)
        self.session.add(vlan)
        await self.session.commit()
        return vlan
    
    async def create_network(
        self,
        network: str,
        prefix_length: int,
        description: str = None,
        vrf_id: int = None,
        vlan_id: int = None,
    ) -> IPNetwork:
        """创建网络.
        
        Args:
            network: 网络地址
            prefix_length: 前缀长度
            description: 描述信息
            vrf_id: VRF ID
            vlan_id: VLAN ID
            
        Returns:
            IPNetwork实例
        """
        # 计算总地址数
        net = ipaddress.ip_network(f"{network}/{prefix_length}")
        if net.version == 4:
            # IPv4: 减去网络地址和广播地址
            total = 2 ** (32 - prefix_length) - 2 if prefix_length < 31 else 2
        else:
            # IPv6: 不扣除特殊地址
            total = 2 ** (128 - prefix_length)
        
        ip_network = IPNetwork(
            network=network,
            prefix_length=prefix_length,
            description=description,
            vrf_id=vrf_id,
            vlan_id=vlan_id,
            total_addresses=total,
        )
        self.session.add(ip_network)
        await self.session.commit()
        return ip_network
    
    async def get_network_utilization(self, network_id: int) -> Tuple[int, int, float]:
        """获取网络使用率.
        
        Args:
            network_id: 网络ID
            
        Returns:
            (总地址数, 已使用地址数, 使用率)
        """
        network = await self.session.get(IPNetwork, network_id)
        if not network:
            raise ValueError(f"Network {network_id} not found")
        
        # 统计已分配地址
        result = await self.session.execute(
            select(func.count(IPAddress.id))
            .where(
                IPAddress.network_id == network_id,
                IPAddress.status == "assigned"
            )
        )
        used = result.scalar() or 0
        
        utilization = (used / network.total_addresses) * 100 if network.total_addresses > 0 else 0
        return network.total_addresses, used, utilization
    
    async def list_networks(
        self,
        vrf_id: int = None,
        vlan_id: int = None,
        is_active: bool = None,
    ) -> List[IPNetwork]:
        """列出网络.
        
        Args:
            vrf_id: 过滤VRF ID
            vlan_id: 过滤VLAN ID
            is_active: 过滤活跃状态
            
        Returns:
            网络列表
        """
        query = select(IPNetwork)
        
        if vrf_id is not None:
            query = query.where(IPNetwork.vrf_id == vrf_id)
        if vlan_id is not None:
            query = query.where(IPNetwork.vlan_id == vlan_id)
        if is_active is not None:
            query = query.where(IPNetwork.is_active == is_active)
        
        result = await self.session.execute(query)
        return list(result.scalars().all())
    
    async def search_ip(self, ip_address: str) -> Optional[IPAddress]:
        """搜索IP地址.
        
        Args:
            ip_address: IP地址字符串
            
        Returns:
            IP地址实例或None
        """
        result = await self.session.execute(
            select(IPAddress).where(IPAddress.address == ip_address)
        )
        return result.scalar_one_or_none()
    
    async def get_network_by_ip(self, ip_address: str) -> Optional[IPNetwork]:
        """根据IP地址获取所属网络.
        
        Args:
            ip_address: IP地址字符串
            
        Returns:
            网络实例或None
        """
        try:
            ip = ipaddress.ip_address(ip_address)
        except ValueError:
            return None
        
        # 查找包含该IP的网络
        networks = await self.list_networks(is_active=True)
        for network in networks:
            net = ipaddress.ip_network(f"{network.network}/{network.prefix_length}")
            if ip in net:
                return network
        
        return None